﻿namespace Grove.Core.Details.Cards {
	using System;
	using System.Collections.Generic;
	using System.Globalization;
	using System.Linq;

	public enum ECardSet {
		// Core Sets
		Magic2013,
		Magic2012,
		Magic2011,
		Magic2010,
		TenthEdition,
		NinthEdition,
		EighthEdition,
		SeventhEdition,
		ClassicSixthEdition,
		FifthEdition,
		FourthEdition,
		RevisedEdition,
		UnlimitedEdition,
		LimitedEditionBeta,
		LimitedEditionAlpha,
		// MTGO
		MTGOMastersEditionIV,
		MTGOMastersEditionIII,
		MTGOMastersEditionII,
		MTGOMastersEdition,
		// Premium Deck Series
		PremiumDeckSeriesGraveborn,
		PremiumDeckSeriesFireAndLightning,
		PremiumDeckSeriesSlivers,
		// Reprint Sets
		DuelsOfThePlaneswalkers,
		Chronicles,
		// “Command Zone” Series
		Planechase2012Edition,
		Commander,
		Archenemy,
		Planechase,
		// From The Vault
		FromTheVaultRealms,
		FromTheVaultLegends,
		FromTheVaultRelics,
		FromTheVaultExiled,
		FromTheVaultDragons,
		// Duel Decks
		DuelDecksIzzetVsGolgari,
		DuelDecksVenserVsKoth,
		DuelDecksAjaniVsNicolBolas,
		DuelDecksKnightsVsDragons,
		DuelDecksElspethVsTezzeret,
		DuelDecksPhyrexiaVsTheCoalition,
		DuelDecksGarrukVsLiliana,
		DuelDecksDivineVsDemonic,
		DuelDecksJaceVsChandra,
		DuelDecksElvesVsGoblins,
		// Theme Decks
		ColdsnapThemeDecks,
		IndependentBox,
		NinthEditionBoxSet,
		EighthEditionBoxSet,
		Deckmasters,
		BeatdownBoxSet,
		BattleRoyaleBoxSet,
		Anthologies,
		MultiverseGiftBoxCards,
		// Un-Serious Sets
		Unhinged,
		Unglued,
		// Alternate Art
		UnhingedAlternateFoils,
		// Beginner Sets
		Starter2000,
		Starter1999,
		PortalThreeKingdoms,
		PortalSecondAge,
		Portal,
		IntroductoryTwoPlayerSet,
		// Not Legal for Tournament Play
		CollectorsEdition,
		InternationalCollectorsEdition,

		// Expansions

		// Innistrad Cycle
		AvacynRestored,
		DarkAscension,
		Innistrad,
		// Scars of Mirrodin
		NewPhyrexia,
		MirrodinBesieged,
		ScarsOfMirrodin,
		// Zendikar Cycle
		RiseOfTheEldrazi,
		Worldwake,
		Zendikar,
		// Shards of Alara
		AlaraReborn,
		Conflux,
		ShardsOfAlara,
		// Shadowmoor Cycle
		Eventide,
		Shadowmoor,
		// Lorwyn Cycle
		Morningtide,
		Lorwyn,
		// Time Spiral Cycle
		FutureSight,
		PlanarChaos,
		TimeSpiral,
		TimeSpiralTimeshifted,
		// Ice Age Cycle
		Coldsnap,
		Alliances,
		IceAge,
		// Ravnica Cycle
		Dissension,
		Guildpact,
		RavnicaCityOfGuilds,
		// Kamigawa Cycle
		SaviorsOfKamigawa,
		BetrayersOfKamigawa,
		ChampionsOfKamigawa,
		// Mirrodin Cycle
		FifthDawn,
		Darksteel,
		Mirrodin,
		// Onslaught Cycle
		Scourge,
		Legions,
		Onslaught,
		// Odyssey Cycle
		Judgment,
		Torment,
		Odyssey,
		// Invasion Cycle
		Apocalypse,
		Planeshift,
		Invasion,
		// Masquerade Cycle
		Prophecy,
		Nemesis,
		MercadianMasques,
		// Artifacts Cycle
		UrzasDestiny,
		UrzasLegacy,
		UrzasSaga,
		// Rath Cycle
		Exodus,
		Stronghold,
		Tempest,
		// Mirage Cycle
		Weatherlight,
		Visions,
		Mirage,
		// Early Sets
		Homelands,
		FallenEmpires,
		TheDark,
		Legends,
		Antiquities,
		ArabianNights
	}

	public interface ICardSet {
		// Core Sets
		bool Magic2013 { get; }
		bool Magic2012 { get; }
		bool Magic2011 { get; }
		bool Magic2010 { get; }
		bool TenthEdition { get; }
		bool NinthEdition { get; }
		bool EighthEdition { get; }
		bool SeventhEdition { get; }
		bool ClassicSixthEdition { get; }
		bool FifthEdition { get; }
		bool FourthEdition { get; }
		bool RevisedEdition { get; }
		bool UnlimitedEdition { get; }
		bool LimitedEditionBeta { get; }
		bool LimitedEditionAlpha { get; }
		// MTGO
		bool MTGOMastersEditionIV { get; }
		bool MTGOMastersEditionIII { get; }
		bool MTGOMastersEditionII { get; }
		bool MTGOMastersEdition { get; }
		// Premium Deck Series
		bool PremiumDeckSeriesGraveborn { get; }
		bool PremiumDeckSeriesFireAndLightning { get; }
		bool PremiumDeckSeriesSlivers { get; }
		// Reprint Sets
		bool DuelsOfThePlaneswalkers { get; }
		bool Chronicles { get; }
		// “Command Zone” Series
		bool Planechase2012Edition { get; }
		bool Commander { get; }
		bool Archenemy { get; }
		bool Planechase { get; }
		// From The Vault
		bool FromTheVaultRealms { get; }
		bool FromTheVaultLegends { get; }
		bool FromTheVaultRelics { get; }
		bool FromTheVaultExiled { get; }
		bool FromTheVaultDragons { get; }
		// Duel Decks
		bool DuelDecksIzzetVsGolgari { get; }
		bool DuelDecksVenserVsKoth { get; }
		bool DuelDecksAjaniVsNicolBolas { get; }
		bool DuelDecksKnightsVsDragons { get; }
		bool DuelDecksElspethVsTezzeret { get; }
		bool DuelDecksPhyrexiaVsTheCoalition { get; }
		bool DuelDecksGarrukVsLiliana { get; }
		bool DuelDecksDivineVsDemonic { get; }
		bool DuelDecksJaceVsChandra { get; }
		bool DuelDecksElvesVsGoblins { get; }
		// Theme Decks
		bool ColdsnapThemeDecks { get; }
		bool IndependentBox { get; }
		bool NinthEditionBoxSet { get; }
		bool EighthEditionBoxSet { get; }
		bool Deckmasters { get; }
		bool BeatdownBoxSet { get; }
		bool BattleRoyaleBoxSet { get; }
		bool Anthologies { get; }
		bool MultiverseGiftBoxCards { get; }
		// Un-Serious Sets
		bool Unhinged { get; }
		bool Unglued { get; }
		// Alternate Art
		bool UnhingedAlternateFoils { get; }
		// Beginner Sets
		bool Starter2000 { get; }
		bool Starter1999 { get; }
		bool PortalThreeKingdoms { get; }
		bool PortalSecondAge { get; }
		bool Portal { get; }
		bool IntroductoryTwoPlayerSet { get; }
		// Not Legal for Tournament Play
		bool CollectorsEdition { get; }
		bool InternationalCollectorsEdition { get; }

		// Expansions

		// Innistrad Cycle
		bool AvacynRestored { get; }
		bool DarkAscension { get; }
		bool Innistrad { get; }
		// Scars of Mirrodin
		bool NewPhyrexia { get; }
		bool MirrodinBesieged { get; }
		bool ScarsOfMirrodin { get; }
		// Zendikar Cycle
		bool RiseOfTheEldrazi { get; }
		bool Worldwake { get; }
		bool Zendikar { get; }
		// Shards of Alara
		bool AlaraReborn { get; }
		bool Conflux { get; }
		bool ShardsOfAlara { get; }
		// Shadowmoor Cycle
		bool Eventide { get; }
		bool Shadowmoor { get; }
		// Lorwyn Cycle
		bool Morningtide { get; }
		bool Lorwyn { get; }
		// Time Spiral Cycle
		bool FutureSight { get; }
		bool PlanarChaos { get; }
		bool TimeSpiral { get; }
		bool TimeSpiralTimeshifted { get; }
		// Ice Age Cycle
		bool Coldsnap { get; }
		bool Alliances { get; }
		bool IceAge { get; }
		// Ravnica Cycle
		bool Dissension { get; }
		bool Guildpact { get; }
		bool RavnicaCityOfGuilds { get; }
		// Kamigawa Cycle
		bool SaviorsOfKamigawa { get; }
		bool BetrayersOfKamigawa { get; }
		bool ChampionsOfKamigawa { get; }
		// Mirrodin Cycle
		bool FifthDawn { get; }
		bool Darksteel { get; }
		bool Mirrodin { get; }
		// Onslaught Cycle
		bool Scourge { get; }
		bool Legions { get; }
		bool Onslaught { get; }
		// Odyssey Cycle
		bool Judgment { get; }
		bool Torment { get; }
		bool Odyssey { get; }
		// Invasion Cycle
		bool Apocalypse { get; }
		bool Planeshift { get; }
		bool Invasion { get; }
		// Masquerade Cycle
		bool Prophecy { get; }
		bool Nemesis { get; }
		bool MercadianMasques { get; }
		// Artifacts Cycle
		bool UrzasDestiny { get; }
		bool UrzasLegacy { get; }
		bool UrzasSaga { get; }
		// Rath Cycle
		bool Exodus { get; }
		bool Stronghold { get; }
		bool Tempest { get; }
		// Mirage Cycle
		bool Weatherlight { get; }
		bool Visions { get; }
		bool Mirage { get; }
		// Early Sets
		bool Homelands { get; }
		bool FallenEmpires { get; }
		bool TheDark { get; }
		bool Legends { get; }
		bool Antiquities { get; }
		bool ArabianNights { get; }

		bool FromSet(string setName);
	}

	[AttributeUsage(AttributeTargets.Property)]
	public class CardSetDetailsAttribute : Attribute {

		public string Abbreviation {
			get;
			private set;
		}

		public string DisplayName {
			get;
			private set;
		}


		public CardSetDetailsAttribute(string abbreviation, string displayName) {
			Abbreviation = abbreviation;
			DisplayName = displayName;
		}

	}

	public class CardSet : ICardSet {
		private static Dictionary<string, string> mSets;

		private readonly List<string> _sets = new List<string>();

		// Core Sets
		[CardSetDetails("m13", "Magic 2013")]
		public bool Magic2013 { get { return FromSet("Magic2013"); } }

		[CardSetDetails("m12", "Magic 2012")]
		public bool Magic2012 { get { return FromSet("Magic 2012"); } }

		[CardSetDetails("m11", "Magic 2011")]
		public bool Magic2011 { get { return FromSet("Magic 2011"); } }

		[CardSetDetails("m10", "Magic 2010")]
		public bool Magic2010 { get { return FromSet("Magic 2010"); } }

		[CardSetDetails("10e", "Tenth Edition")]
		public bool TenthEdition { get { return FromSet("Tenth Edition"); } }

		[CardSetDetails("9e", "Ninth Edition")]
		public bool NinthEdition { get { return FromSet("Ninth Edition"); } }

		[CardSetDetails("8e", "Eighth Edition")]
		public bool EighthEdition { get { return FromSet("Eighth Edition"); } }

		[CardSetDetails("7e", "Seventh Edition")]
		public bool SeventhEdition { get { return FromSet("Seventh Edition"); } }

		[CardSetDetails("6e", "Classic Sixth Edition")]
		public bool ClassicSixthEdition { get { return FromSet("Classic Sixth Edition"); } }

		[CardSetDetails("5e", "Fifth Edition")]
		public bool FifthEdition { get { return FromSet("Fifth Edition"); } }

		[CardSetDetails("4e", "Fourth Edition")]
		public bool FourthEdition { get { return FromSet("Fourth Edition"); } }

		[CardSetDetails("rv", "Revised Edition")]
		public bool RevisedEdition { get { return FromSet("Revised Edition"); } }

		[CardSetDetails("un", "Unlimited Edition")]
		public bool UnlimitedEdition { get { return FromSet("Unlimited Edition"); } }

		[CardSetDetails("be", "Limited Edition Beta")]
		public bool LimitedEditionBeta { get { return FromSet("Limited Edition Beta"); } }

		[CardSetDetails("al", "Limited Edition Alpha")]
		public bool LimitedEditionAlpha { get { return FromSet("Limited Edition Alpha"); } }


		// MTGO
		[CardSetDetails("me4", "MTGO Masters Edition IV")]
		public bool MTGOMastersEditionIV { get { return FromSet("MTGO Masters Edition IV"); } }

		[CardSetDetails("me3", "MTGO Masters Edition III")]
		public bool MTGOMastersEditionIII { get { return FromSet("MTGO Masters Edition III"); } }

		[CardSetDetails("me2", "MTGO Masters Edition II")]
		public bool MTGOMastersEditionII { get { return FromSet("MTGO Masters Edition II"); } }

		[CardSetDetails("med", "MTGO Masters Edition")]
		public bool MTGOMastersEdition { get { return FromSet("MTGO Masters Edition"); } }


		// Special Sets

		// Premium Deck Series
		[CardSetDetails("pd3", "Premium Deck Series: Graveborn")]
		public bool PremiumDeckSeriesGraveborn { get { return FromSet("Premium Deck Series: Graveborn"); } }

		[CardSetDetails("pd2", "Premium Deck Series: Fire and Lightning")]
		public bool PremiumDeckSeriesFireAndLightning { get { return FromSet("Premium Deck Series: Fire and Lightning"); } }

		[CardSetDetails("pds", "Premium Deck Series: Slivers")]
		public bool PremiumDeckSeriesSlivers { get { return FromSet("Premium Deck Series: Slivers"); } }

		// Reprint Sets
		[CardSetDetails("dpa", "Duels of the Planeswalkers")]
		public bool DuelsOfThePlaneswalkers { get { return FromSet("Duels of the Planeswalkers"); } }

		[CardSetDetails("chr", "Chronicles")]
		public bool Chronicles { get { return FromSet("Chronicles"); } }

		// “Command Zone” Series
		[CardSetDetails("pc2", "Planechase 2012 Edition")]
		public bool Planechase2012Edition { get { return FromSet("Planechase 2012 Edition"); } }

		[CardSetDetails("cmd", "Commander")]
		public bool Commander { get { return FromSet("Commander"); } }

		[CardSetDetails("arc", "Archenemy")]
		public bool Archenemy { get { return FromSet("Archenemy"); } }

		[CardSetDetails("pch", "Planechase")]
		public bool Planechase { get { return FromSet("Planechase"); } }

		// From The Vault
		[CardSetDetails("v12", "From the Vault: Realms")]
		public bool FromTheVaultRealms { get { return FromSet("From the Vault: Realms"); } }

		[CardSetDetails("fvl", "From the Vault: Legends")]
		public bool FromTheVaultLegends { get { return FromSet("From the Vault: Legends"); } }

		[CardSetDetails("fvr", "From the Vault: Relics")]
		public bool FromTheVaultRelics { get { return FromSet("From the Vault: Relics"); } }

		[CardSetDetails("fve", "From the Vault: Exiled")]
		public bool FromTheVaultExiled { get { return FromSet("From the Vault: Exiled"); } }

		[CardSetDetails("fvd", "From the Vault: Dragons")]
		public bool FromTheVaultDragons { get { return FromSet("From the Vault: Dragons"); } }

		// Duel Decks
		[CardSetDetails("ddj", "Duel Decks: Izzet vs. Golgari")]
		public bool DuelDecksIzzetVsGolgari { get { return FromSet("Duel Decks: Izzet vs. Golgari"); } }

		[CardSetDetails("ddi", "Duel Decks: Venser vs. Koth")]
		public bool DuelDecksVenserVsKoth { get { return FromSet("Duel Decks: Venser vs. Koth"); } }

		[CardSetDetails("ddh", "Duel Decks: Ajani vs. Nicol Bolas")]
		public bool DuelDecksAjaniVsNicolBolas { get { return FromSet("Duel Decks: Ajani vs. Nicol Bolas"); } }

		[CardSetDetails("ddg", "Duel Decks: Knights vs. Dragons")]
		public bool DuelDecksKnightsVsDragons { get { return FromSet("Duel Decks: Knights vs. Dragons"); } }

		[CardSetDetails("ddf", "Duel Decks: Elspeth vs. Tezzeret")]
		public bool DuelDecksElspethVsTezzeret { get { return FromSet("Duel Decks: Elspeth vs. Tezzeret"); } }

		[CardSetDetails("pvc", "Duel Decks: Phyrexia vs. The Coalition")]
		public bool DuelDecksPhyrexiaVsTheCoalition { get { return FromSet("Duel Decks: Phyrexia vs. The Coalition"); } }

		[CardSetDetails("gvl", "Duel Decks: Garruk vs. Liliana")]
		public bool DuelDecksGarrukVsLiliana { get { return FromSet("Duel Decks: Garruk vs. Liliana"); } }

		[CardSetDetails("dvd", "Duel Decks: Divine vs. Demonic")]
		public bool DuelDecksDivineVsDemonic { get { return FromSet("Duel Decks: Divine vs. Demonic"); } }

		[CardSetDetails("jvc", "Duel Decks: Jace vs. Chandra")]
		public bool DuelDecksJaceVsChandra { get { return FromSet("Duel Decks: Jace vs. Chandra"); } }

		[CardSetDetails("evg", "Duel Decks: Elves vs. Goblins")]
		public bool DuelDecksElvesVsGoblins { get { return FromSet("Duel Decks: Elves vs. Goblins"); } }

		// Theme Decks
		[CardSetDetails("cstd", "Coldsnap Theme Decks")]
		public bool ColdsnapThemeDecks { get { return FromSet("Coldsnap Theme Decks"); } }

		[CardSetDetails("Sets", "Independent Box")]
		public bool IndependentBox { get { return FromSet("Independent Box"); } }

		[CardSetDetails("9eb", "Ninth Edition Box Set")]
		public bool NinthEditionBoxSet { get { return FromSet("Ninth Edition Box Set"); } }

		[CardSetDetails("8eb", "Eighth Edition Box Set")]
		public bool EighthEditionBoxSet { get { return FromSet("Eighth Edition Box Set"); } }

		[CardSetDetails("dm", "Deckmasters")]
		public bool Deckmasters { get { return FromSet("Deckmasters"); } }

		[CardSetDetails("bd", "Beatdown Box Set")]
		public bool BeatdownBoxSet { get { return FromSet("Beatdown Box Set"); } }

		[CardSetDetails("br", "Battle Royale Box Set")]
		public bool BattleRoyaleBoxSet { get { return FromSet("Battle Royale Box Set"); } }

		[CardSetDetails("at", "Anthologies")]
		public bool Anthologies { get { return FromSet("Anthologies"); } }

		[CardSetDetails("mgbc", "Multiverse Gift Box Cards")]
		public bool MultiverseGiftBoxCards { get { return FromSet("Multiverse Gift Box Cards"); } }

		// Un-serious Sets
		[CardSetDetails("uh", "Unhinged")]
		public bool Unhinged { get { return FromSet("Unhinged"); } }

		[CardSetDetails("ug", "Unglued")]
		public bool Unglued { get { return FromSet("Unglued"); } }

		// Alternate Art
		[CardSetDetails("uhaa", "Unhinged Alternate Foils")]
		public bool UnhingedAlternateFoils { get { return FromSet("Unhinged Alternate Foils"); } }

		// Beginner Sets
		[CardSetDetails("st2k", "Starter 2000")]
		public bool Starter2000 { get { return FromSet("Starter 2000"); } }

		[CardSetDetails("st", "Starter 1999")]
		public bool Starter1999 { get { return FromSet("Starter 1999"); } }

		[CardSetDetails("p3k", "Portal Three Kingdoms")]
		public bool PortalThreeKingdoms { get { return FromSet("Portal Three Kingdoms"); } }

		[CardSetDetails("po2", "Portal Second Age")]
		public bool PortalSecondAge { get { return FromSet("Portal Second Age"); } }

		[CardSetDetails("po", "Portal")]
		public bool Portal { get { return FromSet("Portal"); } }

		[CardSetDetails("itp", "Introductory Two-Player Set")]
		public bool IntroductoryTwoPlayerSet { get { return FromSet("Introductory Two-Player Set"); } }

		// Not Legal for Tournament Play
		[CardSetDetails("ced", "Collector's Edition")]
		public bool CollectorsEdition { get { return FromSet("Collector's Edition"); } }

		[CardSetDetails("cedi", "International Collectors' Edition")]
		public bool InternationalCollectorsEdition { get { return FromSet("International Collectors' Edition"); } }


		// Expansions

		// Innistrad Cycle
		[CardSetDetails("avr", "Avacyn Restored")]
		public bool AvacynRestored { get { return FromSet("Avacyn Restored"); } }

		[CardSetDetails("dka", "Dark Ascension")]
		public bool DarkAscension { get { return FromSet("Dark Ascension"); } }

		[CardSetDetails("isd", "Innistrad")]
		public bool Innistrad { get { return FromSet("Innistrad"); } }

		// Scars of Mirrodin
		[CardSetDetails("nph", "New Phyrexia")]
		public bool NewPhyrexia { get { return FromSet("New Phyrexia"); } }

		[CardSetDetails("mbs", "Mirrodin Besieged")]
		public bool MirrodinBesieged { get { return FromSet("Mirrodin Besieged"); } }

		[CardSetDetails("som", "Scars of Mirrodin")]
		public bool ScarsOfMirrodin { get { return FromSet("Scars of Mirrodin"); } }

		// Zendikar Cycle
		[CardSetDetails("roe", "Rise of the Eldrazi")]
		public bool RiseOfTheEldrazi { get { return FromSet("Rise of the Eldrazi"); } }

		[CardSetDetails("wwk", "Worldwake")]
		public bool Worldwake { get { return FromSet("Worldwake"); } }

		[CardSetDetails("zen", "Zendikar")]
		public bool Zendikar { get { return FromSet("Zendikar"); } }

		// Shards of Alara
		[CardSetDetails("arb", "Alara Reborn")]
		public bool AlaraReborn { get { return FromSet("Alara Reborn"); } }

		[CardSetDetails("con", "Conflux")]
		public bool Conflux { get { return FromSet("Conflux"); } }

		[CardSetDetails("ala", "Shards of Alara")]
		public bool ShardsOfAlara { get { return FromSet("Shards of Alara"); } }

		// Shadowmoor Cycle
		[CardSetDetails("eve", "Eventide")]
		public bool Eventide { get { return FromSet("Eventide"); } }

		[CardSetDetails("shm", "Shadowmoor")]
		public bool Shadowmoor { get { return FromSet("Shadowmoor"); } }

		// Lorwyn Cycle
		[CardSetDetails("mor", "Morningtide")]
		public bool Morningtide { get { return FromSet("Morningtide"); } }

		[CardSetDetails("lrw", "Lorwyn")]
		public bool Lorwyn { get { return FromSet("Lorwyn"); } }

		// Time Spiral Cycle
		[CardSetDetails("fst", "Future Sight")]
		public bool FutureSight { get { return FromSet("Future Sight"); } }

		[CardSetDetails("plc", "Planar Chaos")]
		public bool PlanarChaos { get { return FromSet("Planar Chaos"); } }

		[CardSetDetails("tsp", "Time Spiral")]
		public bool TimeSpiral { get { return FromSet("Time Spiral"); } }

		[CardSetDetails("tspts", "Time Spiral \"Timeshifted\"")]
		public bool TimeSpiralTimeshifted { get { return FromSet("Time Spiral \"Timeshifted\""); } }

		// Ice Age Cycle
		[CardSetDetails("cld", "Coldsnap")]
		public bool Coldsnap { get { return FromSet("Coldsnap"); } }

		[CardSetDetails("all", "Alliances")]
		public bool Alliances { get { return FromSet("Alliances"); } }

		[CardSetDetails("ice", "Ice Age")]
		public bool IceAge { get { return FromSet("Ice Age"); } }

		// Ravnica Cycle
		[CardSetDetails("dis", "Dissension")]
		public bool Dissension { get { return FromSet("Dissension"); } }

		[CardSetDetails("gpt", "Guildpact")]
		public bool Guildpact { get { return FromSet("Guildpact"); } }

		[CardSetDetails("rav", "Ravnica: City of Guilds")]
		public bool RavnicaCityOfGuilds { get { return FromSet("Ravnica: City of Guilds"); } }

		// Kamigawa Cycle
		[CardSetDetails("sok", "Saviors of Kamigawa")]
		public bool SaviorsOfKamigawa { get { return FromSet("Saviors of Kamigawa"); } }

		[CardSetDetails("bok", "Betrayers of Kamigawa")]
		public bool BetrayersOfKamigawa { get { return FromSet("Betrayers of Kamigawa"); } }

		[CardSetDetails("chk", "Champions of Kamigawa")]
		public bool ChampionsOfKamigawa { get { return FromSet("Champions of Kamigawa"); } }

		// Mirrodin Cycle
		[CardSetDetails("5dn", "Fifth Dawn")]
		public bool FifthDawn { get { return FromSet("Fifth Dawn"); } }

		[CardSetDetails("dst", "Darksteel")]
		public bool Darksteel { get { return FromSet("Darksteel"); } }

		[CardSetDetails("mrd", "Mirrodin")]
		public bool Mirrodin { get { return FromSet("Mirrodin"); } }

		// Onslaught Cycle
		[CardSetDetails("scg", "Scourge")]
		public bool Scourge { get { return FromSet("Scourge"); } }

		[CardSetDetails("lgn", "Legions")]
		public bool Legions { get { return FromSet("Legions"); } }

		[CardSetDetails("ons", "Onslaught")]
		public bool Onslaught { get { return FromSet("Onslaught"); } }

		// Odyssey Cycle
		[CardSetDetails("jud", "Judgment")]
		public bool Judgment { get { return FromSet("Judgment"); } }

		[CardSetDetails("tor", "Torment")]
		public bool Torment { get { return FromSet("Torment"); } }

		[CardSetDetails("ody", "Odyssey")]
		public bool Odyssey { get { return FromSet("Odyssey"); } }

		// Invasion Cycle
		[CardSetDetails("apc", "Apocalypse")]
		public bool Apocalypse { get { return FromSet("Apocalypse"); } }

		[CardSetDetails("pls", "Planeshift")]
		public bool Planeshift { get { return FromSet("Planeshift"); } }

		[CardSetDetails("inv", "Invasion")]
		public bool Invasion { get { return FromSet("Invasion"); } }

		// Masquerade Cycle
		[CardSetDetails("pcy", "Prophecy")]
		public bool Prophecy { get { return FromSet("Prophecy"); } }

		[CardSetDetails("nms", "Nemesis")]
		public bool Nemesis { get { return FromSet("Nemesis"); } }

		[CardSetDetails("mmq", "Mercadian Masques")]
		public bool MercadianMasques { get { return FromSet("Mercadian Masques"); } }

		// Artifacts Cycle
		[CardSetDetails("uds", "Urza's Destiny")]
		public bool UrzasDestiny { get { return FromSet("Urza's Destiny"); } }

		[CardSetDetails("ulg", "Urza's Legacy")]
		public bool UrzasLegacy { get { return FromSet("Urza's Legacy"); } }

		[CardSetDetails("usg", "Urza's Saga")]
		public bool UrzasSaga { get { return FromSet("Urza's Saga"); } }

		// Rath Cycle
		[CardSetDetails("exo", "Exodus")]
		public bool Exodus { get { return FromSet("Exodus"); } }

		[CardSetDetails("sth", "Stronghold")]
		public bool Stronghold { get { return FromSet("Stronghold"); } }

		[CardSetDetails("tmp", "Tempest")]
		public bool Tempest { get { return FromSet("Tempest"); } }

		// Mirage Cycle
		[CardSetDetails("wth", "Weatherlight")]
		public bool Weatherlight { get { return FromSet("Weatherlight"); } }

		[CardSetDetails("vis", "Visions")]
		public bool Visions { get { return FromSet("Visions"); } }

		[CardSetDetails("mir", "Mirage")]
		public bool Mirage { get { return FromSet("Mirage"); } }

		// Early Sets
		[CardSetDetails("hml", "Homelands")]
		public bool Homelands { get { return FromSet("Homelands"); } }

		[CardSetDetails("fem", "Fallen Empires")]
		public bool FallenEmpires { get { return FromSet("Fallen Empires"); } }

		[CardSetDetails("drk", "The Dark")]
		public bool TheDark { get { return FromSet("The Dark"); } }

		[CardSetDetails("leg", "Legends")]
		public bool Legends { get { return FromSet("Legends"); } }

		[CardSetDetails("atq", "Antiquities")]
		public bool Antiquities { get { return FromSet("Antiquities"); } }

		[CardSetDetails("arn", "Arabian Nights")]
		public bool ArabianNights { get { return FromSet("Arabian Nights"); } }



		public IEnumerable<string> SetNames {
			get { return _sets; }
		}


		public CardSet()
			: this("") {
		}

		public CardSet(CardSet set)
			: this(set.ToString()) {
		}

		private CardSet(string setString) {
			var setNames = ParseSets(setString).ToArray();
			if (setNames.Any()) {
				_sets.AddRange(setNames);
			}
		}


		/// <summary>
		/// Creates a cache of all possible names to speed the lookup based on public fields
		/// </summary>
		public static void LazyLoad() {
			if (mSets != null) {
				return;
			}

			mSets = new Dictionary<string, string>();

			var props = typeof(CardSet).GetProperties();
			foreach (var prop in props) {
				var attribute = prop.GetCustomAttributes(typeof(CardSetDetailsAttribute), false).FirstOrDefault() as CardSetDetailsAttribute;
				if (attribute == null) {
					continue;
				}

				// Add field name itself
				if (mSets.ContainsKey(prop.Name) == false) {
					mSets.Add(prop.Name, prop.Name);
				}

				// Add display name and abbreviation
				string name = attribute.DisplayName;
				if (mSets.ContainsKey(name) == false) {
					mSets.Add(name, prop.Name);
				}
				// Note: Abbreviation is saved uppercased!
				name = attribute.Abbreviation.ToUpperInvariant();
				if (mSets.ContainsKey(name) == false) {
					mSets.Add(name, prop.Name);
				}
			}
		}


		/// <summary>
		/// Parses a string of set names, seperated by comma and/or semicolon
		/// </summary>
		/// <param name="sets"></param>
		/// <returns></returns>
		public static IEnumerable<string> ParseSets(string sets) {
			// Lazyload set names
			LazyLoad();

			var listSets = new List<string>();
			var setNames = sets.Split(new[] { ";", "," }, StringSplitOptions.RemoveEmptyEntries);
			if (setNames.Length == 0) {
				return listSets;
			}

			foreach (var setName in setNames.Select(s => s.Trim())) {
				if (mSets.ContainsKey(setName) == false) {
					throw new Exception("Unknown set in set string: " + setName + " (set string: " + sets + ")");
				}

				// Save the cached name, which is the name of the field
				listSets.Add(mSets[setName]);
			}

			return listSets;
		}

		/// <summary>
		/// Returns the abbreviation for a given set name.
		/// </summary>
		/// <param name="setName"></param>
		/// <returns></returns>
		public static string GetAbbreviation(string setName) {
			// Load all (supported) set names
			LazyLoad();

			var prop = typeof(CardSet).GetProperty(setName);
			if (prop == null) {
				// No propertyname given, but maybe the offical set name?
				if (mSets.ContainsKey(setName) == false) {
					// Nothing we know about
					return null;
				}

				// Get the correct property name
				var propName = mSets[setName];
				prop = typeof(CardSet).GetProperty(propName);
				// This should never happen..
				if (prop == null) {
					return null;
				}
			}

			var attribute = prop.GetCustomAttributes(typeof(CardSetDetailsAttribute), false).FirstOrDefault() as CardSetDetailsAttribute;
			return attribute == null ? null : attribute.Abbreviation;
		}

		/// <summary>
		/// Returns true, if the given abbreviation is a supported & known abbreviation, which means
		/// "valid" for us.
		/// </summary>
		/// <param name="abbreviation"></param>
		/// <returns></returns>
		public static bool IsValidAbbreviation(string abbreviation) {
			LazyLoad();

			// All (supported) abbreviations are stored in our cache!
			return mSets.ContainsKey(abbreviation);
		}


		/// <summary>
		/// Returns true, if the given set is in the defined sets of this instance.
		/// </summary>
		/// <param name="setName"></param>
		/// <returns></returns>
		public bool FromSet(ECardSet setName) {
			return FromSet(setName.ToString());
		}

		/// <summary>
		/// Returns true, if the given set is in the defined sets of this instance.
		/// </summary>
		/// <param name="setName"></param>
		/// <returns></returns>
		public bool FromSet(string setName) {
			// #1 simple check in our current dictionary
			if (_sets.Contains(setName)) {
				return true;
			}

			// Lazyload set names
			LazyLoad();

			// #2 check for a valid set 
			if (mSets.ContainsKey(setName)) {
				// The cache contains the name, so check with the cached field name against our sets
				return _sets.Contains(mSets[setName]);
			}

			// Not found in our sets or cached set names
			// Handle as invalid name
			throw new ArgumentException("No valid set name: " + setName, "setName");
		}


		/// <summary>
		/// Allows the direct cast from a string.
		/// The string will be parsed using ParseSets() through the private CardSet constructor.
		/// </summary>
		/// <param name="cardSets"></param>
		/// <returns></returns>
		public static implicit operator CardSet(string cardSets) {
			return new CardSet(cardSets);
		}

		/// <summary>
		/// Returns all set names semicolon separated
		/// </summary>
		/// <returns></returns>
		public override string ToString() {
			return string.Join(";", _sets);
		}

	}

}